#include <av_player/qls_av_packet_queue.h>

QLsAVPacketQueue::QLsAVPacketQueue()
    : m_firstPkt(nullptr), m_lastPkt(nullptr), m_nbPackets(0), m_size(0),
      m_mutex(SDL_CreateMutex()), m_cond(SDL_CreateCond())
{
}

QLsAVPacketQueue::~QLsAVPacketQueue()
{
    Clear();
    SDL_DestroyMutex(m_mutex);
    SDL_DestroyCond(m_cond);
}

/* 入队 */
void QLsAVPacketQueue::Enqueue(AVPacket *pkt)
{
    if (av_dup_packet(pkt) < 0)
        return;

    AVPacketList *pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));
    if (!pkt1)
        return;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;

    SDL_LockMutex(m_mutex);

    if (!m_lastPkt)
        m_firstPkt = pkt1;
    else
        m_lastPkt->next = pkt1;
    m_lastPkt = pkt1;
    m_nbPackets++;
    m_size += pkt1->pkt.size;
    SDL_CondSignal(m_cond);

    SDL_UnlockMutex(m_mutex);
}

/* 获取队头包 */
bool QLsAVPacketQueue::Get(AVPacket *pkt)
{
    bool res = false;

    SDL_LockMutex(m_mutex);

    if (m_firstPkt) {
        *pkt = m_firstPkt->pkt;
        res = true;
    }

    SDL_UnlockMutex(m_mutex);

    return res;
}

/* 出队 */
void QLsAVPacketQueue::Dequeue()
{
    SDL_LockMutex(m_mutex);

    AVPacketList *pkt1 = m_firstPkt;
    if (pkt1) {
        m_firstPkt = pkt1->next;
        if (!m_firstPkt)
            m_lastPkt = nullptr;
        m_nbPackets--;
        m_size -= pkt1->pkt.size;
        av_free(pkt1);
    }

    SDL_UnlockMutex(m_mutex);
}

/* 提取对头包 = 获取队头包 + 出队 */
bool QLsAVPacketQueue::PopFront(AVPacket *pkt)
{
    bool res = false;

    SDL_LockMutex(m_mutex);

    AVPacketList *pkt1 = m_firstPkt;
    if (pkt1) {
        *pkt = m_firstPkt->pkt;

        m_firstPkt = pkt1->next;
        if (!m_firstPkt)
            m_lastPkt = nullptr;
        m_nbPackets--;
        m_size -= pkt1->pkt.size;
        av_free(pkt1);

        res = true;
    }

    SDL_UnlockMutex(m_mutex);

    return res;
}

/* 清空 */
void QLsAVPacketQueue::Clear()
{
    AVPacketList *pkt, *pkt1;

    SDL_LockMutex(m_mutex);

    for (pkt = m_firstPkt; pkt != NULL; pkt = pkt1) {
        pkt1 = pkt->next;
        av_packet_unref(&pkt->pkt);
        av_freep(&pkt);
    }
    m_lastPkt = NULL;
    m_firstPkt = NULL;
    m_nbPackets = 0;
    m_size = 0;

    SDL_UnlockMutex(m_mutex);
}
